07. Testing Error Handling

L5 P4 A06 Testing Error Handling V3

In this step you'll test your application reacts appropriately when there's an error (such as data being unavailable from the network).

Step 1: Add an error flag to test double

  1. Open test > data > source > FakeTestRepository.
  2. Add a boolean flag called shouldReturnError and set it initially to false, which means that by default an error is not returned.

FakeTestRepository.kt

private var shouldReturnError = false
  1. Create a setReturnError method that changes whether or not the repository should return errors:

FakeTestRepository.kt

fun setReturnError(value: Boolean) {
    shouldReturnError = value
}
  1. Wrap getTask and getTasks in if statements so that if shouldReturnError is true, the method returns Result.Error:

FakeTestRepository.kt

override suspend fun getTask(taskId: String, forceUpdate: Boolean): Result<Task> {
    if (shouldReturnError) {
        return Error(Exception("Test exception"))
    }
    tasksServiceData[taskId]?.let {
        return Success(it)
    }
    return Error(Exception("Could not find task"))
}

override suspend fun getTasks(forceUpdate: Boolean): Result<List<Task>> {
    if (shouldReturnError) {
        return Error(Exception("Test exception"))
    }
    return Success(tasksServiceData.values.toList())
}

Step 2: Write a test for returned Error

In StatisticsViewModel, there are two LiveData booleans (error and empty):

StatisticsViewModel.kt

class StatisticsViewModel(
    private val tasksRepository: TasksRepository
) : ViewModel() {

    private val tasks: LiveData<Result<List<Task>>> = tasksRepository.observeTasks()

    // Other variables...    

    val error: LiveData<Boolean> = tasks.map { it is Error }
    val empty: LiveData<Boolean> = tasks.map { (it as? Success)?.data.isNullOrEmpty() }

    // Rest of the code...    
}

These represent whether or not tasks loaded properly. If there is an error, error and empty should both be true.

  1. Open StatisticsViewModelTest.
  2. Create a new test called loadStatisticsWhenTasksAreUnavailable_callErrorToDisplay
  3. Call setReturnErrors() on tasksRepository, setting it to true.
  4. Call statisticsViewModel.refresh() to trigger a data load.
  5. Check that statisticsViewModel.empty and statisticsViewModel.error are both true.

The full code for this test is below:

StatisticsViewModelTest.kt

@Test
fun loadStatisticsWhenTasksAreUnavailable_callErrorToDisplay() {
    // Make the repository return errors.
    tasksRepository.setReturnError(true)
    statisticsViewModel.refresh()

    // Then empty and error are true (which triggers an error message to be shown).
    assertThat(statisticsViewModel.empty.getOrAwaitValue(), `is`(true))
    assertThat(statisticsViewModel.error.getOrAwaitValue(), `is`(true))
}
  1. Run your test and observe it passing!